package com.bangcommunity.bbframe.common.utils;

import com.bangcommunity.bbframe.common.utils.lang.StringUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * 数字相关工具
 * 
 * @author tanghc
 */
public class MathUtils {

    /**
     * BigDecimal 相加。考虑npe
     *
     */
    public static BigDecimal add(BigDecimal... nums) {
        return add(Arrays.asList(nums));
    }
    public static BigDecimal max(BigDecimal... nums) {
        return max(Arrays.asList(nums));
    }
    public static BigDecimal min(BigDecimal... nums) {
        return min(Arrays.asList(nums));
    }
    public static BigDecimal add(List<BigDecimal> nums) {
        BigDecimal sum = BigDecimal.ZERO;
        if (null != nums) {
            for (BigDecimal n : nums) {
                if (null != n) {
                    sum = sum.add(n);
                }
            }
        }
        return sum;
    }
    public static BigDecimal max(List<BigDecimal> nums) {
        if(null != nums){
            return nums.parallelStream().max(BigDecimal::compareTo).get();
        }
        return null;
    }
    public static BigDecimal min(List<BigDecimal> nums) {
        if(null != nums){
            return nums.parallelStream().min(BigDecimal::compareTo).get();
        }
        return null;
    }

    public static Number add(Number... nums) {
        Long sum = 0L;
        if (null != nums) {
            for (Number n : nums) {
                if (null != n) {
                    sum += n.longValue();
                }
            }
        }
        return sum;
    }
    public static Number max(Number... nums) {
        if(null != nums && nums.length > 0){
            return Arrays.asList(nums).parallelStream().max(((o1, o2) -> new Long(o1.longValue()).compareTo(o2.longValue()))).get();
        }
        return null;
    }
    public static Number min(Number... nums) {
        if(null != nums && nums.length > 0){
            return Arrays.asList(nums).parallelStream().min(((o1, o2) -> new Long(o1.longValue()).compareTo(o2.longValue()))).get();
        }
        return null;
    }

    public static BigDecimal trimToZero(BigDecimal amount) {
        if (null == amount) {
            return BigDecimal.ZERO;
        }
        return amount;
    }

    public static BigDecimal trimToZero(Number number) {
        if (null == number) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(number.toString());
    }

    public static BigDecimal percentToBigDecimal(String percentString) {
        try {
            if (StringUtils.isBlank(percentString) || !percentString.endsWith("%")) {
                return BigDecimal.ZERO;
            }
            return new BigDecimal(percentString.substring(0, percentString.lastIndexOf("%")));
        } catch (Exception e) {
        }
        return BigDecimal.ZERO;
    }

    /**
     * BigDecimal null转成0
     */
    public static BigDecimal convertNullToZero(BigDecimal v) {
        return null == v ? BigDecimal.ZERO : v;
    }

    public static int fastAbs(final int value) {
        return value & Integer.MAX_VALUE;
    }

    public static long roundToNearestMultipleOf(final long num, final long multipleOf) {
        if (num < 0) {
            throw new IllegalArgumentException("num cannot be negative");
        }
        if (multipleOf < 1) {
            throw new IllegalArgumentException("cannot round to nearest multiple of values less than 1");
        }
        if (num < multipleOf) {
            return multipleOf;
        }
        if ((num % multipleOf) >= (multipleOf / 2.0)) {
            return (num + multipleOf) - (num % multipleOf);
        } else {
            return num - (num % multipleOf);
        }
    }

    public static final double EARTHRADIUS = 6370996.81;

    /**
     * 根据经纬度计算两点距离
     * @param longitude1 第一个点经度
     * @param latitude1 第一个点 纬度
     * @param longitude2 第二个点经度
     * @param latitude2 第二个点纬度
     * @return
     */
    public static double geoDistance(double longitude1, double latitude1, double longitude2, double latitude2) {

        longitude1 = _getLoop(longitude1, -180, 180);
        latitude1 = _getRange(latitude1, -74, 74);
        longitude2 = _getLoop(longitude2, -180, 180);
        latitude2 = _getRange(latitude2, -74, 74);

        double x1, x2, y1, y2;
        x1 = degreeToRad(longitude1);
        y1 = degreeToRad(latitude1);
        x2 = degreeToRad(longitude2);
        y2 = degreeToRad(latitude2);

        return EARTHRADIUS * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1) * Math.cos(y2) * Math.cos(x2 - x1)));
    }

    /**
     * 将latitude值限定在a,b之间，纬度使用
     */
    public static double _getRange(double latitude, Integer a, Integer b) {
        if (a != null) {
            latitude = Math.max(latitude, a);
        }
        if (b != null) {
            latitude = Math.min(latitude, b);
        }
        return latitude;
    }

    /**
     * 将longitude值限定在a,b之间，经度使用
     */
    public static double _getLoop(double longitude, Integer a, Integer b) {
        while (longitude > b) {
            longitude -= b - a;
        }
        while (longitude < a) {
            longitude += b - a;
        }
        return longitude;
    }

    /**
     * 将度转化为弧度
     * 
     * @param degree
     * @return
     */
    public static double degreeToRad(double degree) {
        return Math.PI * degree / 180;
    }

    /**
     * 将弧度转化为度
     * 
     * @param rad
     * @return
     */
    public static double radToDegree(double rad) {
        return (180 * rad) / Math.PI;
    }

    // public static Integer toInt(Number number){
    // if(number == null){
    // return null;
    // }
    // return number.intValue();
    // }
    public static void main(String[] args) {
        System.out.println(percentToBigDecimal("12.3%"));
        System.out.println(geoDistance(116.423241,39.921576,116.53535,39.979542));
    }
}
